package com.runvp.handler;

import com.alibaba.fastjson.JSONObject;
import com.runvp.common.constant.ConstantRedisKey;
import com.runvp.common.enums.*;
import com.runvp.common.model.tcp.MessageReceiveBody;
import com.runvp.common.model.tcp.MessageResBody;
import com.runvp.common.model.vo.app.BizCreateOrderVO;
import com.runvp.common.util.BigDecimalUtil;
import com.runvp.common.util.ToolUtils;
import com.runvp.common.utils.Threads;
import com.runvp.service.app.AppClientService;
import com.runvp.service.biz.domain.BizCustomer;
import com.runvp.service.biz.domain.BizCustomerWallet;
import com.runvp.service.biz.domain.BizDeviceCargo;
import com.runvp.service.biz.domain.BizOrder;
import com.runvp.service.out.OutHandler;
import com.runvp.service.tcp.TcpService;
import com.runvp.system.service.ISysConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

@Slf4j
@Component
public class CmdSwipeCardChargeHandler {

    @Autowired
    private OutHandler outHandler;
    @Autowired
    private TcpService tcpService;
    @Autowired
    private AppClientService appClientService;
    @Autowired
    private ISysConfigService configService;
    /**
     * 设备刷卡请求充电处理
     * @param parseBody
     * @return MessageResBody
     */
    public MessageResBody handle(MessageReceiveBody parseBody){
        log.info("设备刷卡请求充电处理:::receiveBody:{}",JSONObject.toJSONString(parseBody));
        String batchNo = System.nanoTime()+"";
        String sn = parseBody.getTerminalId();
        long id = ToolUtils.objTOLong(tcpService.instanceRedisUtil().getCacheObject(ConstantRedisKey.DEVICE_SN_ID+sn));
        tcpService.addBizTcpRecord(parseBody.setBatchNo(batchNo));
        MessageResBody resBody = buildRes(id,parseBody.getBodyJson());
        resBody.setDeviceId(id);
        resBody.setTerminalId(sn);
        tcpService.addBizTcpRecord(resBody.setBatchNo(batchNo));
        log.info("设备刷卡请求充电处理:::resBody:{}",JSONObject.toJSONString(resBody));
        return resBody;
    }
    /**
     * 结构结果体
     * {
     * ‘cid’:“xxx”,//字符串，卡号
     * ‘amt’:3,//此次充电金额，整型，刷一次卡代表一元
     * ‘po’:1,//整型，下发的充电端口
     * }
     * @return str
     */
    private JSONObject buildBody(Long deviceId,JSONObject bodyJson){
        String cid = bodyJson.getString("cid");
        int amt = ToolUtils.toInt(bodyJson.getInteger("amt"));
        int po = ToolUtils.toInt(bodyJson.getInteger("po"));
        JSONObject map = new JSONObject();
        map.put("amt",0);
        map.put("oid",0);
        BizCustomer customer = tcpService.instanceIBizCustomerService().selectBizCustomerByOpenId(cid);
        if(null == customer){
            map.put("rs",0);
            map.put("er",3);
            log.error("卡号【{}】未和设备绑定",cid);
            return map;
        }
        if(!EnableStatus.ENABLE.getCode().equals(customer.getStatus())){
            map.put("rs",0);
            map.put("er",1);
            log.error("刷卡充电:::卡号【{}】未激活",cid);
            return map;
        }
        //根据卡号查询余额
        BizCustomerWallet wallet = tcpService.instanceIBizCustomerWalletService().customerWallet(customer.getId());
        BigDecimal balance = wallet.getBalance();
        BigDecimal newBalance = BigDecimalUtil.div(balance,BigDecimalUtil.vf(amt));
//        BigDecimal use = BigDecimalUtil.vf(configService.selectConfigByKey("cloudCardWeight"));
        if(newBalance.doubleValue() < 0){
            map.put("rs",0);
            map.put("er",2);
            log.error("刷卡充电:::卡号【{}】余额不足",cid);
            return map;
        }
        map.put("amt",newBalance);
        //下单
        BizCreateOrderVO createOrderVO = new BizCreateOrderVO();
        try {
            BizDeviceCargo query = new BizDeviceCargo();
            query.setDeviceId(deviceId);
            query.setNumber(po);
            List<BizDeviceCargo> cargos = tcpService.instanceIBizDeviceCargoService().selectBizDeviceCargoList(query);
            if(CollectionUtils.isEmpty(cargos)){
                map.put("rs",0);
                map.put("er",3);
                log.error("刷卡充电:::设备【{}】端口【{}】未配置",deviceId,po);
                return map;
            }
            createOrderVO.setDeviceId(deviceId);
            createOrderVO.setCargoId(cargos.get(0).getId());
            createOrderVO.setOa(BigDecimalUtil.vf(amt));
            createOrderVO.setCustomerId(customer.getId());
            createOrderVO.setPayChannel(PayChannel.PAY_CLOUD_CARD.getCode());
            createOrderVO.setPayPlat("");
            createOrderVO.setSource(DataSource.CLOUD_CARD_CENTER.getCode());
            log.info("刷卡充电:::创建订单参数: {}", JSONObject.toJSONString(createOrderVO));
            Map<String, Object> res = appClientService.createOrder(createOrderVO);
            String orderNo = ToolUtils.toStr(res.get("orderNo"));
            log.info("刷卡充电:::订单创建完毕,订单号:【{}】",orderNo);
            map.put("oid",orderNo);
            BizOrder order = (BizOrder) res.get("order");
            //800ms后发送启动充电指令
            Threads.sleep(1500);
            outHandler.executeOut(order, order.getAmount());
            res.remove("order");
            map.put("rs",1);
            map.put("er",0);
            log.info("刷卡充电:::订单【{}】启动充电指令发送完毕",orderNo);
        } catch (Exception e) {
            log.error("刷卡充电:::创建订单失败:{}", e.getMessage());
        }
        return map;
    }


    /**
     * 默认报文
     *
     * @return MessageResBody
     */
    public MessageResBody buildRes(Long deviceId,JSONObject bodyJson) {
        MessageResBody resBody = new MessageResBody(NettyType.SERVER_RECEIVE_DEVICE.getCode(), NettyCmd.SERVER_RES_SWIPE_CARD_CHARGE.getCode());
        resBody.setDid("000000000000");
        resBody.setVersion("01");
        resBody.setBodyJson(buildBody(deviceId,bodyJson)).buildRes();
        log.info("服务器组装刷卡充电报文完毕");
        return resBody;
    }

}
